﻿//-----------------------------------------------------------------------
// <copyright>
//     Copyright (c) Artur Mustafin. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Expressions.Compiler
{
    using System.Collections;
    using System.Collections.Generic;

    using Internal;

    /// <summary>
    /// A stream class
    /// </summary>
    public sealed class Rules<T> : IEnumerable
    {
        /// <summary>
        /// Rule definition delegate
        /// </summary> 
        /// <returns>A token stream</returns>
        public delegate Tokens<T> Definition();

        /// <summary>
        /// Rules list
        /// </summary>
        private readonly List<Rule<T>> _rules;

        private readonly Nonterminal<T> _nonterminal;

        internal Rule<T> this[Definition definition]
        {
            get
            {
                foreach (Rule<T> rule in _rules)
                {
                    if (rule.Definition == definition)
                    {
                        return rule;
                    }
                }
                return new Rule<T>(_nonterminal, definition);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Rules"/> class.
        /// </summary>
        internal Rules(Nonterminal<T> nonterminal)
        {
            _nonterminal = nonterminal;
            _rules = new List<Rule<T>>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Rules"/> class.
        /// </summary>
        public Rules()
        {
            _rules = new List<Rule<T>>();
        }

        /// <summary>
        /// Adds the specified rule.
        /// </summary>
        /// <param name="rule">The input rule</param>
        public void Add(Rules<T>.Definition rule)
        {
            _rules.Add(rule);
        }

        /// <summary>
        /// Adds the specified rule.
        /// </summary>
        /// <param name="rule">The input rule</param>
        internal void Add(Nonterminal<T> nonterminal, Rules<T>.Definition rule)
        {
            _rules.Add(Rule<T>.GetRule(nonterminal, rule));
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _rules.GetEnumerator();
        }

        /// <summary>
        /// Sets the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        internal void Set(IEnumerable<Rule<T>> value)
        {
            foreach (Rule<T> item in value)
            {
                Add(_nonterminal, item.Definition);
            }
        }

        internal void Clear()
        {
            _rules.Clear();
        }

        internal IEnumerable<Rule<T>> Definitions
        {
            get
            {
                return _rules;
            }
        }
    }

    /// <summary>
    /// A stream class
    /// </summary>
    public sealed class Rules : IEnumerable
    {
        /// <summary>
        /// Rule definition delegate
        /// </summary> 
        /// <returns>A token stream</returns>
        public delegate Tokens Definition();

        /// <summary>
        /// Rules list
        /// </summary>
        private readonly List<Rule> _rules;

        private readonly Nonterminal _nonterminal;

        internal Rule this[Definition definition]
        {
            get
            {
                foreach (Rule rule in _rules)
                {
                    if (rule.Definition == definition)
                    {
                        return rule;
                    }
                }
                return new Rule(_nonterminal, definition);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Rules"/> class.
        /// </summary>
        internal Rules(Nonterminal nonterminal)
        {
            _nonterminal = nonterminal;
            _rules = new List<Rule>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Rules"/> class.
        /// </summary>
        public Rules()
        {
            _rules = new List<Rule>();
        }

        /// <summary>
        /// Adds the specified rule.
        /// </summary>
        /// <param name="rule">The input rule</param>
        public void Add(Rules.Definition rule)
        {
            _rules.Add(rule);
        }

        /// <summary>
        /// Adds the specified rule.
        /// </summary>
        /// <param name="rule">The input rule</param>
        internal void Add(Nonterminal nonterminal, Rules.Definition rule)
        {
            _rules.Add(Rule.GetRule(nonterminal, rule));
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _rules.GetEnumerator();
        }

        /// <summary>
        /// Sets the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        internal void Set(IEnumerable<Rule> value)
        {
            foreach (Rule item in value)
            {
                Add(_nonterminal, item.Definition);
            }
        }

        internal void Clear()
        {
            _rules.Clear();
        }

        internal IEnumerable<Rule> Definitions
        {
            get
            {
                return _rules;
            }
        }
    }
}
